package org.xmap.ui.control;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.TextBox;

import org.xmap.app.Env;
import org.xmap.ui.Theme;
import org.xmap.ui.UIUtil;
import org.xmap.ui.ViewManager;
import org.xmap.ui.base.Event;
import org.xmap.ui.base.Window;
import org.xmap.ui.listener.TextFieldListener;

/**
 * <p>文本输入控件，早期的设计是在低级控件里面输入数字和字母，但是不能输入中文，现在改成在高级控件输入。</p>
 * @author Zealot
 * @version 1.0
 */
public class TextField extends Window implements CommandListener {

    /**
     * 下划线的宽度。
     */
    private static int UNDERLINE_WIDTH = 10;
    /**
     * 输入框的标题。
     */
    protected String title;
    /**
     * 存储输入的字符的缓存。
     */
    protected StringBuffer text;
    /**
     * 输入字符字数限制。
     */
    protected int maxSize;
    /**
     * 输入字符类型限制。
     */
    protected int constraints;
    /**
     * 输入框文本的颜色。
     */
    protected int textColor;
    /**
     * 输入框边框的颜色。
     */
    protected int lineColor;
    /**
     * 带有焦点的时候的背景颜色值。
     */
    protected int focusBgColor;
    /**
     * 是否显示边框。
     */
    protected boolean drawRect;
    /**
     * 是否显示标题。
     */
    protected boolean drawTitle;
    /**
     * 输入的对齐方式，一般都是左对齐或居中。
     */
    protected int align;
    /**
     * 是否透明，透明指不绘制背景颜色。
     */
    protected boolean transparent;
    /**
     * 按键监听器。
     */
    protected TextFieldListener listener;

    /**
     * 指定标题、初始文字、监听器、输入框锚点横坐标、纵坐标、宽度、高度的构造函数。
     * @param title String 标题文字。
     * @param text String 初始文字。
     * @param listener TextFieldListener 监听器。
     * @param maxSize int 最大字符数。
     * @param constraints int 锚点类型。
     * @param x int 输入框锚点横坐标。
     * @param y int 输入框锚点纵坐标。
     * @param width int 输入框宽度。
     * @param height int 输入框高度。
     */
    public TextField(String title, String text, TextFieldListener listener, int maxSize, int constraints,
                     int x, int y, int width, int height) {
        this(title, text, listener, maxSize, constraints, x, y, width, height, Window.ORIENT_LEFT_UP);
    }

    /**
     * 指定标题、初始文字、监听器、输入框锚点横坐标、纵坐标、宽度、高度和锚点类型的构造函数。
     * @param title String 标题文字。
     * @param text String 初始文字。
     * @param listener TextFieldListener 监听器。
     * @param maxSize int 最大字符数。
     * @param constraints int 锚点类型。
     * @param x int 输入框锚点横坐标。
     * @param y int 输入框锚点纵坐标。
     * @param width int 输入框宽度。
     * @param height int 输入框高度。
     * @param orient int 锚点类型。
     */
    public TextField(String title, String text, TextFieldListener listener, int maxSize, int constraints,
                     int x, int y, int width, int height, int orient) {
        super(x, y, width, height, orient);
        super.setCanFocus(true);
        this.title = title;
        this.text = new StringBuffer(32);
        this.setText(text);
        this.maxSize = maxSize;
        this.constraints = constraints;
        this.textColor = 0xff000000;
        this.lineColor = Theme.instance.defaultLineColor;
        this.focusBgColor = Theme.instance.textfieldFocusBgColor;
        this.drawRect = true;
        this.drawTitle = true;
        this.align = Window.ALIGN_CENTER;
        this.transparent = false;
        this.listener = listener;
        TextField.UNDERLINE_WIDTH = Env.instance.defaultFont.stringWidth("_");
    }

    /**
     * 设置标题的文字。
     * @param text String 标题的文字。
     */
    public void setTitle(String text) {
        this.title = text;
    }

    /**
     * 获得标题的文字。
     * @return String 标题的文字。
     */
    public String getTitle() {
        return this.title;
    }

    /**
     * 设置输入框的文字。
     * @param text String 输入框的文字。
     */
    public void setText(String text) {
        this.text.setLength(0);
        if (text != null) {
            this.text.append(text);
        }
    }

    /**
     * 获得输入框的文字。
     * @return String 输入框的文字。
     */
    public String getText() {
        return this.text.toString();
    }

    /**
     * 设置文字的颜色。
     * @param color int 文字的颜色。
     */
    public void setTextColor(int color) {
        this.textColor = color;
    }

    /**
     * 获得文字的颜色。
     * @return int 文字的颜色。
     */
    public int getTextColor() {
        return this.textColor;
    }

    /**
     * 设置边框的颜色。
     * @param lineColor int 边框的颜色。
     */
    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
    }

    /**
     * 获得边框的颜色。
     * @return int 边框的颜色。
     */
    public int getLineColor() {
        return this.lineColor;
    }

    /**
     * 设置拥有焦点时的背景颜色值。
     * @param focusBgColor 拥有焦点时的背景颜色值。
     */
    public void setFocusBgColor(int focusBgColor) {
        this.focusBgColor = focusBgColor;
    }

    /**
     * 获得拥有焦点时的背景颜色值。
     * @return int 拥有焦点时的背景颜色值。
     */
    public int getFocusBgColor() {
        return this.focusBgColor;
    }

    /**
     * 设置是否显示边框。
     * @param isDrawRect boolean 是否显示边框。
     */
    public void setDrawRect(boolean isDrawRect) {
        this.drawRect = isDrawRect;
    }

    /**
     * 获得是否显示边框。
     * @return boolean 是否显示边框。
     */
    public boolean getDrawRect() {
        return this.drawRect;
    }

    /**
     * 设置是否显示标题。
     * @param drawTitle boolean 是否显示标题。
     */
    public void setDrawTitle(boolean drawTitle) {
        this.drawTitle = drawTitle;
    }

    /**
     * 获得是否显示标题。
     * @return boolean 是否显示标题。
     */
    public boolean getDrawTitle() {
        return this.drawTitle;
    }

    /**
     * 设置输入框文字的对齐方式，默认是左对齐。
     * @param align int 输入框文字的对齐方式。
     */
    public void setAlign(int align) {
        switch (align) {
        case Window.ALIGN_RIGHT:
            this.align = Window.ALIGN_RIGHT;
            break;
        case Window.ALIGN_CENTER:
            this.align = Window.ALIGN_CENTER;
            break;
        default:
            this.align = Window.ALIGN_LEFT;
            break;
        }
    }

    /**
     * 获得输入框文字的对齐方式。
     * @return int 输入框文字的对齐方式。
     */
    public int getAlign() {
        return this.align;
    }

    /**
     * 设置输入框是否为透明，透明的意思是不用背景颜色填充背景。
     * @param transparent boolean 是否透明。
     */
    public void setTransparent(boolean transparent) {
        this.transparent = transparent;
    }

    /**
     * 获得输入框是否为透明。
     * @return boolean 是否透明。
     */
    public boolean getTransparent() {
        return this.transparent;
    }

    /**
     * 删除一个字符。
     */
    public void deleteOne() {
        if (this.text.length() > 0) {
            this.text.setLength(this.text.length() - 1);
            if (this.text.length() == 0) {
                if (this.listener != null) {
                    this.listener.textCleaned();
                }
            }
        }
    }

    /**
     * 删除所有字符。
     */
    public void deleteAll() {
        if (this.text.length() > 0) {
            this.text.setLength(0);
            if (this.listener != null) {
                this.listener.textCleaned();
            }
        }
    }

    /**
     * 绘制函数。
     * @param g Graphics 图形句柄。
     */
    public void draw(Graphics g) {
        g.setFont(Env.instance.defaultFont);
        if (!this.transparent) {
            if (super.getFocus()) {
                g.setColor(this.focusBgColor);
                g.fillRect(0, 0, this.getRect().width, this.getRect().height);
            } else {
                g.setColor(this.bgColor);
                g.fillRect(0, 0, this.getRect().width, this.getRect().height);
            }
        }
        if (this.bgImage != null) {
            if (super.getBackgroundImageStretch() || super.getBackgroundImageCenter()) {
                g.drawImage(this.bgImage, this.getRect().width >> 1, this.getRect().height >> 1, Graphics.VCENTER | Graphics.HCENTER);
            } else {
                for (int i = 0; i < this.getRect().width; i += this.bgImage.getWidth()) {
                    for (int j = 0; j < this.getRect().height; j += this.bgImage.getHeight()) {
                        g.drawImage(this.bgImage, i, j, Graphics.LEFT | Graphics.TOP);
                    }
                }
            }
        }
        g.setColor(this.textColor);
        String s = null;
        if (this.drawTitle) {
            s = this.title;
            if (s == null) {
                s = this.text.toString();
            } else {
                s += this.text.toString();
            }
        } else {
            s = this.text.toString();
        }
        switch (this.align) {
        case Window.ALIGN_LEFT:
            UIUtil.draw(g, s,
                        0, this.getRect().height >> 1,
                        Graphics.LEFT, Graphics.VCENTER);
            if (super.getFocus()) {
                if (System.currentTimeMillis() % 1000 > 500) {
                    if (s.length() == 0) {
                        UIUtil.draw(g, "_",
                                    0, this.getRect().height >> 1,
                                    Graphics.LEFT, Graphics.VCENTER);
                    } else {
                        int x = Env.instance.defaultFont.stringWidth(s);
                        UIUtil.draw(g, "_",
                                    x, this.getRect().height >> 1,
                                    Graphics.LEFT, Graphics.VCENTER);
                    }
                }
            }
            break;
        case Window.ALIGN_CENTER:
            UIUtil.draw(g, s,
                        this.getRect().width >> 1, this.getRect().height >> 1,
                        Graphics.HCENTER, Graphics.VCENTER);
            if (super.getFocus()) {
                if (System.currentTimeMillis() % 1000 > 500) {
                    if (s.length() == 0) {
                        UIUtil.draw(g, "_",
                                    this.getRect().width >> 1, this.getRect().height >> 1,
                                    Graphics.HCENTER, Graphics.VCENTER);
                    } else {
                        int x = Env.instance.defaultFont.stringWidth(s) >> 1;
                        UIUtil.draw(g, "_",
                                    (this.getRect().width >> 1) + x, this.getRect().height >> 1,
                                    Graphics.LEFT, Graphics.VCENTER);
                    }
                }
            }
            break;
        case Window.ALIGN_RIGHT:
            UIUtil.draw(g, s,
                        this.getRect().width - TextField.UNDERLINE_WIDTH, this.getRect().height >> 1,
                        Graphics.RIGHT, Graphics.VCENTER);
            if (super.getFocus()) {
                if (System.currentTimeMillis() % 1000 > 500) {
                    UIUtil.draw(g, "_", (this.getRect().width), this.getRect().height >> 1,
                                Graphics.RIGHT, Graphics.VCENTER);
                }
            }
            break;
        }
        if (this.drawRect) {
            g.setColor(this.lineColor);
            g.drawRect(0, 0, this.getRect().width - 1, this.getRect().height - 1);
        }
    }

    public void commandAction(Command command, Displayable displayable) {
        if (command.getLabel().equals("确定")) {
            TextBox tb = (TextBox) displayable;
            this.text.setLength(0);
            this.text.append(tb.getString());
            ViewManager.instance.getDisplay().setCurrent(ViewManager.instance);
        } else if (command.getLabel().equals("返回")) {
            ViewManager.instance.getDisplay().setCurrent(ViewManager.instance);
        }
    }

    /**
     * 输入框控件按键处理函数。
     * @param flag boolean 是按下还是抬起。
     * @param keyCode int 按键代码。
     * @param gameAction int 动作代码。
     * @return boolean 是否处理该事件。
     */
    public boolean keyEvent(boolean flag, int keyCode, int gameAction) {
        if (flag) {
//                if (keyCode >= Canvas.KEY_NUM0 && keyCode <= Canvas.KEY_NUM9) {
//                    this.text.append((char) keyCode);
//                    if (this.text.length() == 1) {
//                        if (this.listener != null) {
//                            this.listener.inputBegan();
//                        }
//                    } else {
//                        if (this.listener != null) {
//                            this.listener.textInput(keyCode);
//                        }
//                    }
//                    return true;
//                }
            switch (gameAction) {
            case Canvas.UP:
                if (this.owner != null) {
                    this.owner.requestLossFocus(this, true);
                }
                return true;
            case Canvas.DOWN:
                if (this.owner != null) {
                    this.owner.requestLossFocus(this, false);
                }
                return true;
            default:
                TextBox tb = new TextBox(this.title, this.getText(), this.maxSize, this.constraints);
                tb.addCommand(new Command("确定", Command.OK, 1));
                tb.addCommand(new Command("返回", Command.EXIT, 1));
                tb.setCommandListener(this);
                ViewManager.instance.getDisplay().setCurrent(tb);
                return true;
            }
        }
        return false;
    }

    /**
     * 触笔事件处理函数，在输入框区域内的触笔事件都被处理，如果当前没有焦点，还会向拥有该控件的视图发出焦点转移通知。
     * @param ev Event 触笔事件。
     * @return boolean 是否处理该事件。
     */
    public boolean pointerEvent(Event ev) {
        boolean result = false;
        switch (ev.type) {
        case Event.POINTER_PRESSED:
            if (this.getRect().collideWith(ev.param1, ev.param2)) {
                if (!super.getFocus()) {
                    if (this.owner != null) {
                        this.owner.requestGetFocus(this);
                    }
                }
                result = true;
            }
            break;
        case Event.POINTER_RELEASED:
            break;
        case Event.POINTER_DRAGGED:
            break;
        }
        return result;
    }
}
